﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Data;
using System.Data.SqlClient;
using AForge.Controls;
using AForge.Video;
using AForge.Video.DirectShow;

namespace AutoParkingManagement
{
    public partial class LaneEntry : UserControl
    {
        #region Private members
        private EntryExit _entryExit;
        private bool _isLeft;
        private bool _captured = false;
        private bool _saved=true;
        private string _message = String.Empty;
        private string _urlFrontCamera = String.Empty;
        private string _urlRearCamera = String.Empty;
        private string _plateNo = String.Empty;

        private int RFID
        {
            get
            {
                if (_isLeft)
                {
                    return AppConfig.RFIDLEFT;
                }
                else
                {
                    return AppConfig.RFIDRIGHT;
                }
            }
        }

        /// <summary>
        /// Use card reader and get CardID        /// 
        /// </summary>
        /// <returns></returns>
        private string GetCardID()
        {
            _entryExit.Message = String.Empty;
            if (AppConfig.HasCardReader == "0") //only for demo
            {
                StringBuilder sb = new StringBuilder();
                sb.Append("SELECT TOP 1 CardID FROM Card ");
                object obj = SqlHelper.ExecuteScalar(CommandType.Text, sb.ToString(), null);
                if (obj == null) return Guid.Empty.ToString();
                return obj.ToString();
            }
            else //Read card to get card id
            {
                string strCardID = String.Empty;
                string strMessage = String.Empty;
                if (!DLL1356.GetCardIDByCardReader(RFID, ref strCardID, ref strMessage))
                {
                    strCardID = String.Empty;
                    _entryExit.Message = strMessage;
                }
                return strCardID;
            }
            //return Guid.NewGuid().ToString();

        }

        private Guid GetCardTypeByCardID(string cardID)
        {
            StringBuilder sb = new StringBuilder();
            sb.Append("SELECT CardTypeID FROM Card ");
            sb.Append("WHERE CardID = @CardID");

            SqlParameter parm = new SqlParameter("@CardID", SqlDbType.NVarChar,50);
            parm.Value = cardID;

            object obj = SqlHelper.ExecuteScalar(CommandType.Text, sb.ToString(), parm);
            if (obj == null) return Guid.Empty;
            return (Guid)obj;
        }

        private string GetCardTypeName(Guid cardTypeID)
        {
            StringBuilder sb = new StringBuilder();
            sb.Append("SELECT [Name] FROM CardType ");
            sb.Append("WHERE CardTypeID = @CardTypeID");


            SqlParameter parm = new SqlParameter("@CardTypeID", SqlDbType.UniqueIdentifier);
            parm.Value = cardTypeID;

            object objCardTypeName = SqlHelper.ExecuteScalar(CommandType.Text, sb.ToString(), parm);
            if (objCardTypeName == null) return String.Empty;
            return objCardTypeName.ToString();
        }

        private string GetPlateNumberByCardID(string cardID)
        {
            StringBuilder sb = new StringBuilder();
            sb.Append("SELECT PlateNumber FROM EntryExit ");
            sb.Append("WHERE CardID = @CardID AND ExitTime IS NULL");
            SqlParameter parm = new SqlParameter("@CardID", SqlDbType.NVarChar,50);
            parm.Value = cardID;

            object objPlateNumber = SqlHelper.ExecuteScalar(CommandType.Text, sb.ToString(), parm);
            if (objPlateNumber == null) return String.Empty;
            return objPlateNumber.ToString();
        }

        /// <summary>
        /// Read information from card
        /// </summary>
        private void GetCardInfo()
        {            
            _entryExit.Card = new Card();
            _entryExit.Card.Id = GetCardID();
            _entryExit.Card.CardType = new CardType();
            _entryExit.Card.CardType.Id = GetCardTypeByCardID(_entryExit.Card.Id);
        }

        private bool CanEntry()
        {            
            ///////////////////////////////////////
            StringBuilder sb = new StringBuilder();
            sb.Append("SELECT Count(ID) FROM EntryExit ");            
            sb.Append("WHERE CardID = @CardID ");
            sb.Append("AND ExitTime IS NULL");

            SqlParameter parm = new SqlParameter("@CardID", SqlDbType.NVarChar,50);
            parm.Value = _entryExit.Card.Id;
            object objEntry = SqlHelper.ExecuteScalar(CommandType.Text, sb.ToString(), parm);
            return ((int)objEntry == 0);
        }

        /// <summary>
        /// Check platenumber that not yet exit
        /// </summary>
        /// <returns></returns>
        private bool IsExistedPlateNumber(string plateNumber)
        {
            ///////////////////////////////////////
            StringBuilder sb = new StringBuilder();
            sb.Append("SELECT Count(ID) FROM EntryExit ");
            sb.Append("WHERE dbo.ufn_StripCharacters(PlateNumber, '^a-z0-9')  = dbo.ufn_StripCharacters(@PlateNumber, '^a-z0-9') ");
            sb.Append("AND ExitTime IS NULL");

            SqlParameter parm = new SqlParameter("@PlateNumber", SqlDbType.NVarChar, 50);
            parm.Value = plateNumber;
            object objEntry = SqlHelper.ExecuteScalar(CommandType.Text, sb.ToString(), parm);
            return ((int)objEntry > 0);
        }

        private bool CardActive(string cardID)
        {
            StringBuilder sb = new StringBuilder();
            sb.Append("SELECT Count(CardID) FROM Card ");
            sb.Append("WHERE CardID = @CardID And Active = 1");            
            SqlParameter parm = new SqlParameter("@CardID", SqlDbType.NVarChar, 50);
            parm.Value = cardID;
            object objEntry = SqlHelper.ExecuteScalar(CommandType.Text, sb.ToString(), parm);
            return ((int)objEntry > 0);
        }

        /// <summary>
        /// Process image and return platenumber
        /// </summary>
        /// <returns></returns>
        private string GetPlateNumber(string imagePath)
        {
            if (AppConfig.HasImageToText == "0")
            {
                //return String.Format("{0}", DateTime.Now.ToString("ssB-ss.mm.ss"));
                return String.Empty;
            }
            string strPlateNumber = String.Empty;
            try
            {
                int status;
                int iID_Cam = 1;
                bool Plate_Flag = false;
                String Image = imagePath;
                int iCorrect = 0;
                int iTime = 0;
                String Time = String.Empty;
                String Plate_number = String.Empty;
                String Vehicle = String.Empty;
                status = DLL1356.get_image(iID_Cam, ref Plate_Flag, ref Image, ref iCorrect, ref iTime,
                                  ref Time, ref Plate_number, ref Vehicle);
                if (status == 950) return Plate_number;                
            }
            catch (Exception ex)
            {
                throw ex;
                //MessageBox.Show(ex.ToString());
            }
            return strPlateNumber;
        }

        private DateTime GetEntryTime(string cardID)
        {
            StringBuilder sb = new StringBuilder();
            sb.Append("SELECT TOP 1 EntryTime FROM EntryExit ");
            sb.Append("WHERE CardID = @CardID AND ExitTime IS NULL ");
            sb.Append("ORDER BY EntryTime DESC");
            SqlParameter parm = new SqlParameter("@CardID", SqlDbType.NVarChar, 50);
            parm.Value = cardID;
            object obj = SqlHelper.ExecuteScalar(CommandType.Text, sb.ToString(), parm);
            return (DateTime)obj;
        }

        private void ResetImages()
        {
            picFront.Appearance.ImageBackground = Properties.Resources.NoImage;
            picFront.Tag = null;
            picRear.Appearance.ImageBackground = Properties.Resources.NoImage;
            if (_entryExit != null)
            {                
                _entryExit.Card = null;
                _entryExit.RearImageEntry = null;
                _entryExit.RearImageExit = null;                
                GC.Collect();
            }
        }

        #endregion

        #region Properties

        public bool IsLeft
        {
            get
            {
                return _isLeft;
            }
            set
            {
                _isLeft = value;
            }
        }

        public string URLFrontCamera
        {
            get
            {
                return _urlFrontCamera;
            }
            set
            {
                _urlFrontCamera = value;
            }
        }

        public string URLRearCamera
        {
            get
            {
                return _urlRearCamera;
            }
            set
            {
                _urlRearCamera = value;
            }
        }

        public EntryExit EntryExit
        {
            get
            {
                return _entryExit;
            }
            set
            {
                _entryExit = value;
            }
        }

        public bool Saved
        {
            get
            {
                return _saved;
            }
            set
            {
                _saved = value;
            }
        }

        public string Message
        {
            get
            {
                return _message;
            }
            set
            {
                _message = value;
            }
        }        

        #endregion

        #region Public members
        public void StartCameras()
        {
            string strNumberDat = String.Format(@"{0}\{1}", Application.StartupPath, "DataFile0to91.dat");
            string strCharDat = String.Format(@"{0}\{1}", Application.StartupPath, "DataFileAtoZ1.dat");
            string[] databasePaths = new string[2] { strNumberDat, strCharDat };        
            // create video source
            if (AppConfig.HasIPCamera == "0")//only for demo without ip camera
            {
                FileVideoSource fileSourceFront = new FileVideoSource(AppConfig.FrontVideoFile);
                IPCameraHelper.OpenVideoSource(webCamFront, fileSourceFront);
                FileVideoSource fileSourceRear = new FileVideoSource(AppConfig.RearVideoFile);
                IPCameraHelper.OpenVideoSource(webCamRear, fileSourceRear);
            }
            else
            {
                MJPEGStream mjpegSourceFront = new MJPEGStream(_urlFrontCamera);
                MJPEGStream mjpegSourceRear = new MJPEGStream(_urlRearCamera);
                IPCameraHelper.OpenVideoSource(webCamFront, mjpegSourceFront);
                IPCameraHelper.OpenVideoSource(webCamRear, mjpegSourceRear);
            }            
        }
        /// <summary>
        /// Capture plate Number
        /// </summary>
        /// <returns>plate number</returns>
        public string CapturePlateNumber()
        {
            try
            {
                Cursor.Current = Cursors.WaitCursor;
                //_plateNo = String.Empty;
                _message = String.Empty;                
                Image frontImage = IPCameraHelper.CaptureImage(webCamFront);
                string strSide = "phải";
                if (_isLeft) strSide = "trái";
                if (frontImage == null)
                {
                    _message = String.Format("Vui lòng kiểm tra lại camera phía trước (bên {0})", strSide);
                    return String.Empty;
                }

                Image rearImage = IPCameraHelper.CaptureImage(webCamRear);
                if (rearImage == null)
                {
                    _message = String.Format("Vui lòng kiểm tra lại camera phía sau (bên {0})", strSide);
                    return String.Empty;
                }

                frontImage = Common.ResizeImage(frontImage, picFront.Size.Width, picFront.Size.Height);
                rearImage = Common.ResizeImage(rearImage, picRear.Size.Width, picRear.Size.Height);
                
                picFront.Appearance.ImageBackground = frontImage;
                picRear.Appearance.ImageBackground = rearImage;                
                /////////////////////////////////
                if (_entryExit == null)
                {
                    _entryExit = new EntryExit();
                }                
                _captured = true;                             
                _entryExit.FrontImageEntry = Common.ImageToByteArray(frontImage);
                _entryExit.RearImageEntry = Common.ImageToByteArray(rearImage);
                //string strRearImagePath = Common.SaveImage(rearImage);
                _entryExit.PlateNumber = _plateNo;                
                //webCamRear_GetImageInfo(null, null);
                _entryExit.EntryTime = Common.GetSystemDBTime();
                _saved = false;
                return _entryExit.PlateNumber;
            }
            catch (Exception ex)
            {
                throw ex;
            }
            finally
            {

                Cursor.Current = Cursors.Default;
            }
        }

        private string GetParkingFloorById(Guid id)
        {
            string sql = @"SELECT [Name]      
                  FROM [ParkingFloor]
                  WHERE ParkingFloorID=@ParkingFloorID";
            SqlParameter parm = new SqlParameter("@ParkingFloorID", SqlDbType.UniqueIdentifier);
            parm.Value = id;
            object obj = SqlHelper.ExecuteScalar(CommandType.Text, sql, parm);
            if (obj == null) return String.Empty;
            return obj.ToString();
        }

        /// <summary>
        /// Save data
        /// </summary>
        /// <returns></returns>
        public bool SavePlateNumber()
        {            
            if (!_saved)
            {
                _message = String.Empty;
                GetCardInfo();
                if (!String.IsNullOrEmpty(_entryExit.Message))
                {
                    _message = _entryExit.Message;
                    return false;
                }
                ////////////////////////////////////////
                StringBuilder sb = new StringBuilder();        
                /////////////////////////
                if (!CardActive(_entryExit.Card.Id))
                {
                    sb.Append("Xe này không được vào cổng");
                    sb.Append("\nvì thẻ này chưa được kích hoạt.");
                    _message = sb.ToString();
                    return false;
                }
                /////////////////////////

                if (!CanEntry())
                {
                    sb = new StringBuilder();
                    sb.Append("Xe này không được vào cổng");
                    sb.Append("\nvì thẻ này chưa ra khỏi bãi xe");
                    sb.Append("\n Thẻ này đang sử dụng cho biển số {0}");
                    _message = String.Format(sb.ToString(), GetPlateNumberByCardID(_entryExit.Card.Id));
                    return false;
                }

                if (IsExistedPlateNumber(_entryExit.PlateNumber))
                {
                    sb = new StringBuilder();
                    sb.Append("Xe này không được vào cổng");
                    sb.Append("\nVì biển số {0} chưa ra khỏi bãi xe");
                    _message = String.Format(sb.ToString(), _entryExit.PlateNumber);
                    return false;
                }
                //////////////////////////
                MonthCard monthCard = new MonthCard();
                monthCard = monthCard.GetByPlateNumber(_entryExit.PlateNumber);
                string parkingFloor = String.Empty;
                if (monthCard != null) //ve thang
                {
                    parkingFloor = GetParkingFloorById(monthCard.ParkingFloorId);
                    if (!parkingFloor.ToUpper().Equals(AppConfig.ParkingFloor.ToUpper()))
                    {
                        sb = new StringBuilder();
                        sb.Append("Xe này không được vào cổng");
                        sb.Append("\nVì xe vé tháng gởi sai hầm");
                        _message = sb.ToString();
                        return false;
                    }
                }
                monthCard = null;
                GC.Collect();
                /////////////////////////
                //Save data to card
                if (AppConfig.HasCardReader == "1" && !DLL1356.WritePlate(RFID, String.Empty, ref _message))
                {
                    _entryExit.Message = _message;
                    return false;
                }
                /////////////////////////
                sb = new StringBuilder();
                sb.Append("INSERT INTO EntryExit(CardID, PlateNumber, FrontImageEntry, RearImageEntry, CardType, ParkingFloor, EntryUpdateUser) ");
                sb.Append("VALUES (@CardID, @PlateNumber, @FrontImageEntry, @RearImageEntry, @CardType, @ParkingFloor, @EntryUpdateUser)");
                SqlParameter[] parms = new SqlParameter[7];
                parms[0] = new SqlParameter("@CardID",SqlDbType.NVarChar,50);                
                parms[0].Value = _entryExit.Card.Id;

                parms[1] = new SqlParameter("@PlateNumber",SqlDbType.NVarChar,50);                
                parms[1].Value = _entryExit.PlateNumber;

                parms[2] = new SqlParameter("@FrontImageEntry", SqlDbType.Image);                
                parms[2].Value = Common.DBNullImage(_entryExit.FrontImageEntry);

                parms[3] = new SqlParameter("@RearImageEntry",SqlDbType.Image);                
                parms[3].Value = Common.DBNullImage(_entryExit.RearImageEntry);

                parms[4] = new SqlParameter("@CardType",SqlDbType.NVarChar,50);                
                parms[4].Value = GetCardTypeName(_entryExit.Card.CardType.Id);

                parms[5] = new SqlParameter("@ParkingFloor", SqlDbType.NVarChar, 50);
                parms[5].Value = AppConfig.ParkingFloor;

                parms[6] = new SqlParameter("@EntryUpdateUser",SqlDbType.UniqueIdentifier);
                parms[6].Value = MainParent.EmpWorking.Employee.Id;

                SqlHelper.ExecuteNonQuery(CommandType.Text, sb.ToString(), parms);
                _entryExit.EntryTime = GetEntryTime(_entryExit.Card.Id);
                _saved = true;
                _message = "Ghi thẻ xong.\nVui lòng đưa thẻ cho khách hàng.";
            }
            ResetImages();
            return _saved;
        }

        /// <summary>
        /// Reset lane
        /// </summary>
        public void ResetLane()
        {
            ResetImages();
            _message = string.Empty;
            _saved = true;
        }

        /// <summary>
        /// Stop cameras
        /// </summary>
        public void StopCameras()
        {
            try
            {
                IPCameraHelper.CloseVideoSource(webCamFront);
                IPCameraHelper.CloseVideoSource(webCamRear);
            }
            catch (Exception ex)
            {
                
                throw ex;
            }
        }

        #endregion

        #region Events
        private void LaneEntry_Load(object sender, EventArgs e)
        {
            try
            {
                picFront.Appearance.ImageBackground = Properties.Resources.NoImage;
                picRear.Appearance.ImageBackground = Properties.Resources.NoImage;                
                if (!_isLeft)
                {
                    pnlLeft.Dock = DockStyle.Right;
                    pnlRight.Dock = DockStyle.Left;
                }
            }
            catch (Exception ex)
            {
                throw ex;
                //MessageBox.Show(ex.ToString());
            }
        }        

        //private void webCamRear_GetImageInfo(object sender, IPACam.InfoEventArgs e)
        //{
        //    try
        //    {
        //        if (e.Plate_Number_Flag && e.Plate.Count>0 && !String.IsNullOrEmpty(e.Bienso))
        //        {
        //            _plateNo = e.Bienso;
        //        }
        //    }
        //    catch
        //    {
        //    }
        //}
        #endregion

        #region "Constructors"
        public LaneEntry(bool isLeft)
        {
            InitializeComponent();
            CheckForIllegalCrossThreadCalls = false;
            _isLeft = isLeft;
        }
        #endregion 
        
    }
}
